<template>
  <q-page padding>

    <q-dialog v-model="visible" persistent>
      <q-card style="min-width: 25em">
        <q-form @submit="onSubmit">
          <q-card-section>
            <div class="text-h6">{{ $t('generators') }}</div>
          </q-card-section>

          <q-card-section>
            <q-input v-model="form.name" :label="$t('name')" lazy-rules
            :rules="[val => val && val.length > 0 || $t('inputText')]" />
            <q-input v-model="form.comment" :label="$t('comment')" lazy-rules
            :rules="[val => val && val.length > 0 || $t('inputText')]" />
            <q-input v-model="form.domain" :label="$t('domain')" lazy-rules
            :rules="[val => val && val.length > 0 || $t('inputText')]" />
            <q-input v-model="form.reference" :label="$t('reference')" lazy-rules
            :rules="[val => val && val.length > 0 || $t('inputText')]" />
          </q-card-section>

          <q-card-actions align="right">
            <q-btn title="cancel" type="reset" unelevated :label="$t('cancel')" v-close-popup />
            <q-btn title="submit" type="submit" flat :label="$t('submit')" color="primary" />
          </q-card-actions>
        </q-form>
      </q-card>
    </q-dialog>

    <!-- preview -->
    <q-dialog v-model="previewVisible">
      <q-card style="width: 50%; max-width: 800px;">
        <q-card-section class="row items-center q-pb-none">
          <div class="text-h6">{{ $t('preview') }}</div>
          <q-space />
          <q-btn icon="sym_r_close" flat round dense v-close-popup />
        </q-card-section>

        <q-card-section style="height: 600px; max-height: 600px;" class="scroll">
          <q-tabs v-model="tab" align="justify" no-caps dense>
            <q-tab v-for="(item, index) in renderedTemplates" :key="index" :name="item.id"
              :label="item.name + item.suffix" />
          </q-tabs>
          <q-tab-panels v-model="tab" animated>
            <q-tab-panel v-for="(item, index) in renderedTemplates" :key="index" :name="item.id" style="padding: 0;">
              <CodeRender :content="item.content" />
            </q-tab-panel>
          </q-tab-panels>
        </q-card-section>
      </q-card>
    </q-dialog>

    <!-- config -->
    <q-dialog v-model="configVisible">
      <q-card style="max-width: 65em;">
        <q-card-section class="row items-center q-pb-none">
          <div class="text-h6">{{ $t('config') }}</div>
          <q-space />
          <q-btn icon="sym_r_close" flat round dense v-close-popup />
        </q-card-section>

        <q-card-section style="max-height: 70vh;" class="scroll">
          <q-table flat :rows="fields" :columns="configColumns" row-key="id" binary-state-sort hide-pagination
            class="full-width">

            <template v-slot:header="props">
              <q-tr :props="props">
                <q-th v-for="col in props.cols" :key="col.name" :props="props">
                  {{ $t(col.label) }}
                </q-th>
              </q-tr>
            </template>

            <template v-slot:body-cell-queryable="props">
              <q-td :props="props">
                <q-checkbox dense v-model="props.row.queryable" />
              </q-td>
            </template>
            <template v-slot:body-cell-editable="props">
              <q-td :props="props">
                <q-checkbox dense v-model="props.row.editable" />
              </q-td>
            </template>
          </q-table>
        </q-card-section>

        <q-card-actions align="right">
          <q-btn title="cancel" type="reset" unelevated :label="$t('cancel')" v-close-popup />
          <q-btn title="submit" type="submit" flat :label="$t('submit')" color="primary" />
        </q-card-actions>
      </q-card>
    </q-dialog>

    <q-table flat ref="tableRef" :title="$t('schemas')" :rows="rows" :columns="columns" row-key="id"
      v-model:pagination="pagination" :loading="loading" :filter="filter" binary-state-sort @request="onRequest"
      class="full-width">
      <template v-slot:top-right>
        <q-input dense debounce="300" v-model="filter" placeholder="Search">
          <template v-slot:append>
            <q-icon name="sym_r_search" />
          </template>
        </q-input>
        <q-btn title="create" round padding="xs" class="q-mx-sm" color="primary" :disable="loading" icon="sym_r_add"
          @click="saveRow()" />
        <q-btn title="refresh" round padding="xs" flat color="primary" :disable="loading" icon="sym_r_refresh"
          @click="refresh" />
        <q-btn title="import" round padding="xs" flat color="primary" class="q-mx-sm" :disable="loading"
          icon="sym_r_database_upload" @click="importRow" />
        <q-btn title="export" round padding="xs" flat color="primary" icon="sym_r_file_export" @click="exportTable" />
      </template>

      <template v-slot:header="props">
        <q-tr :props="props">
          <q-th v-for="col in props.cols" :key="col.name" :props="props">
            {{ $t(col.label) }}
          </q-th>
        </q-tr>
      </template>
      <template v-slot:body-cell-templates="props">
        <q-td :props="props">
          <q-chip v-for="(item, index) in visibleArray(props.row.templates, 3)" :key="index" color="primary"
            text-color="white" class="q-mr-sm" size="sm">
            {{ formatTemplates(item as number) }}
          </q-chip>
          <template v-if="props.row.templates.length > 3">
            <q-chip color="primary" text-color="white" class="q-mr-sm" size="sm">
              + {{ props.row.templates.length - 3 }}
              <q-tooltip>
                <q-chip v-for="(item, index) in props.row.templates.slice(3)" :key="index" text-color="white"
                  class="q-mr-sm" size="sm">
                  {{ formatTemplates(item) }}
                </q-chip>
              </q-tooltip>
            </q-chip>
          </template>
        </q-td>
      </template>
      <template v-slot:body-cell-lastModifiedDate="props">
        <q-td :props="props">
          {{ props.row.lastModifiedDate ? date.formatDate(props.row.lastModifiedDate, 'YYYY-MM-DD HH:mm') : '-' }}
        </q-td>
      </template>
      <template v-slot:body-cell-id="props">
        <q-td :props="props">
          <q-btn title="modify" padding="xs" flat round color="primary" icon="sym_r_edit" @click="saveRow(props.row.id)"
            class="q-mt-none" />
          <q-btn title="config" padding="xs" flat round color="primary" icon="sym_r_rule_settings"
            @click="configRow(props.row.id)" class="q-mt-none q-mx-sm" />
          <q-btn title="preview" padding="xs" flat round color="primary" icon="sym_r_visibility"
            @click="previewRow(props.row.id)" class="q-mt-none" />
          <q-btn title="delete" padding="xs" flat round color="negative" icon="sym_r_delete"
            @click="removeRow(props.row.id)" class="q-mt-none q-ml-sm" />
        </q-td>
      </template>
    </q-table>
  </q-page>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import type { QTableProps } from 'quasar'
import { useQuasar, date, exportFile } from 'quasar'
import CodeRender from 'components/CodeRender.vue'
import {
  retrieveSchemas, retrieveSchemaFields, retrieveSchemaPreview, fetchSchema,
  createSchema, modifySchema, removeSchema
} from 'src/api/schemas'
import { retrieveTemplates } from 'src/api/templates'
import type { Schema, Field, Template } from 'src/types'
import { visibleArray } from 'src/utils'

const $q = useQuasar()

const visible = ref<boolean>(false)
const importVisible = ref<boolean>(false)
const previewVisible = ref<boolean>(false)
const configVisible = ref<boolean>(false)

const tableRef = ref()
const rows = ref<QTableProps['rows']>([])
const filter = ref('')
const loading = ref<boolean>(false)

const fields = ref<Array<Field>>([])
const templates = ref<Array<Template>>([])
const renderedTemplates = ref<Array<Template>>([])
const tab = ref('')

const initialValues: Schema = {
  id: undefined,
  name: '',
  comment: '',
  reference: '',
  domain: '',
  templates: []
}
const form = ref<Schema>({ ...initialValues })

const pagination = ref({
  sortBy: 'id',
  descending: true,
  page: 1,
  rowsPerPage: 7,
  rowsNumber: 0
})

const columns: QTableProps['columns'] = [
  { name: 'name', label: 'name', align: 'left', field: 'name', sortable: true },
  { name: 'comment', label: 'comment', align: 'left', field: 'comment' },
  { name: 'domain', label: 'domain', align: 'left', field: 'domain' },
  { name: 'reference', label: 'reference', align: 'left', field: 'reference' },
  { name: 'templates', label: 'templates', align: 'left', field: 'templates' },
  { name: 'lastModifiedDate', label: 'lastModifiedDate', align: 'center', field: 'lastModifiedDate' },
  { name: 'id', label: 'actions', field: 'id' }
]

const configColumns: QTableProps['columns'] = [
  { name: 'name', label: 'name', align: 'left', field: 'name', sortable: true },
  { name: 'dataType', label: 'type', align: 'left', field: 'dataType' },
  { name: 'length', label: 'length', align: 'left', field: 'length' },
  { name: 'nullable', label: 'nullable', align: 'left', field: 'nullable' },
  { name: 'comment', label: 'comment', align: 'left', field: 'comment' },
  { name: 'fieldType', label: 'fieldType', align: 'left', field: 'fieldType' },
  { name: 'formType', label: 'formType', align: 'left', field: 'formType' },
  { name: 'queryable', label: 'queryable', align: 'left', field: 'queryable' },
  { name: 'editable', label: 'editable', align: 'left', field: 'editable' }
]

onMounted(() => {
  tableRef.value.requestServerInteraction()
  loadTemplages()
})

/**
 * 查询列表
 */
async function onRequest(props: Parameters<NonNullable<QTableProps['onRequest']>>[0]) {
  loading.value = true

  const { page, rowsPerPage, sortBy, descending } = props.pagination
  const filter = props.filter

  const params = { page, size: rowsPerPage, sortBy, descending }

  retrieveSchemas({ ...params }, filter).then(res => {
    pagination.value.page = page
    pagination.value.rowsPerPage = rowsPerPage
    pagination.value.sortBy = sortBy
    pagination.value.descending = descending

    rows.value = res.data.content
    pagination.value.rowsNumber = res.data.totalElements
  }).finally(() => {
    loading.value = false
  })
}

function refresh() {
  tableRef.value.requestServerInteraction()
}

async function loadSchemaFields(id: number) {
  retrieveSchemaFields(id).then(res => {
    fields.value = res.data
  })
}

async function loadTemplages() {
  retrieveTemplates({ page: 1, size: 99 }).then(res => {
    templates.value = res.data.content
  })
}

async function saveRow(id?: number) {
  form.value = { ...initialValues }

  visible.value = true
  // You can populate the form with existing user data based on the id
  if (id) {
    fetchSchema(id).then(res => { form.value = res.data })
  }
}

function importRow() {
  importVisible.value = true
}

function previewRow(id: number) {
  previewVisible.value = true
  retrieveSchemaPreview(id).then(res => {
    renderedTemplates.value = res.data
    tab.value = res.data[0].id
  })
}

function configRow(id: number) {
  configVisible.value = true
  loadSchemaFields(id)
}

function removeRow(id: number) {
  loading.value = true
  removeSchema(id).finally(() => { loading.value = false })
}

function onSubmit() {
  if (form.value.id) {
    modifySchema(form.value.id, form.value)
  } else {
    createSchema(form.value)
  }

  // Close the dialog after submitting
  visible.value = false
}


function wrapCsvValue(val: string, formatFn?: (val: string, row?: string) => string, row?: string) {
  let formatted = formatFn !== void 0 ? formatFn(val, row) : val

  formatted = formatted === void 0 || formatted === null ? '' : String(formatted)

  formatted = formatted.split('"').join('""')

  return `"${formatted}"`
}

function exportTable() {
  if (!columns || !rows.value || columns.length === 0 || rows.value.length === 0) {
    // Handle the case where columns or rows are undefined or empty
    console.error('Columns or rows are undefined or empty.')
    return
  }
  // naive encoding to csv format
  const content = [columns.map(col => wrapCsvValue(col.label))]
    .concat(rows.value.map(row => columns.map(col =>
      wrapCsvValue(typeof col.field === 'function' ? col.field(row) : row[col.field === void 0 ? col.name : col.field],
        col.format,
        row
      )).join(','))
    ).join('\r\n')

  const status = exportFile(
    'table-export.csv',
    content,
    'text/csv'
  )

  if (status !== true) {
    $q.notify({
      message: 'Browser denied file download...',
      color: 'negative',
      icon: 'warning'
    })
  }
}

/**
   * format templates
   * @param cellValue cell value
   */
function formatTemplates(cellValue: number): string {
  const templateItem = templates.value.find(item => item.id === cellValue)
  return templateItem ? templateItem.name + templateItem.suffix : ''
}

</script>
